// Package transport
// Author liuzhiyong
// Date 2023/11/25
// Description 传输层 处理不同的协议, 转换请求和响应参数, 绑定端点
package transport

import (
	"context"
	"encoding/json"
	"gitee.com/liu_zy_developer/go-kit-demo/endpoint"
	"gitee.com/liu_zy_developer/go-kit-demo/middleware"
	"gitee.com/liu_zy_developer/go-kit-demo/proto"
	"gitee.com/liu_zy_developer/go-kit-demo/service"
	grpctransport "github.com/go-kit/kit/transport/grpc"
	httptransport "github.com/go-kit/kit/transport/http"
	"github.com/gorilla/mux"
	"go.uber.org/zap"
	"golang.org/x/time/rate"
	"net/http"
)

// ------------------HTTP请求---------------------------
// decodeSumRequest 解码求和的参数
func decodeSumRequest(ctx context.Context, r *http.Request) (interface{}, error) {
	var request endpoint.SumRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		return nil, err
	}
	return request, nil
}

// decodeCountRequest 解析拼接字符串参数
func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) {
	var request endpoint.ConcatRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		return nil, err
	}
	return request, nil
}

// encodeResponse 编码响应参数, 将参数写入响应
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
	zap.L().Info("HTTP 响应编码", zap.Any("response", response))
	return json.NewEncoder(w).Encode(response)
}

// NewHTTPServer 创建HTTP服务
func NewHTTPServer(svc service.AddService) http.Handler {
	// sum处理器 --> 处理HTTP请求
	// 创建原始的端点
	sum := endpoint.MakeSumEndpoint(svc)

	// 日志中间件会生成一个增强型的代理端点(装饰器模式)
	sum = middleware.LoggingMiddleWare(zap.L())(sum)            // 日志
	sum = middleware.RateMiddleware(rate.NewLimiter(1, 1))(sum) // 限流
	sum = middleware.RecoveryMiddleWare(zap.L())(sum)           // recover 异常

	sumHandler := httptransport.NewServer(
		sum,              // 端点
		decodeSumRequest, // 传输层解析参数函数
		encodeResponse,   // 传输层编码响应参数函数
	)

	// 拼接字符串处理器	--> 处理HTTP请求
	concatHandler := httptransport.NewServer(
		endpoint.MakeConcatEndpoint(svc),
		decodeCountRequest,
		encodeResponse,
	)

	// use github.com/gorilla/mux
	r := mux.NewRouter()
	r.Handle("/sum", sumHandler).Methods("POST")
	r.Handle("/concat", concatHandler).Methods("POST")
	return r
}

// BindEndpointsAndStartServer 绑定传输层和端点, 生成处理器,绑定http路由, 启动服务
//func BindEndpointsAndStartServer() {
//	svc := service.addServiceImpl{}
//
//	// sum处理器 --> 处理HTTP请求
//	sumHandler := httptransport.NewServer(
//		endpoint.MakeSumEndpoint(svc), // 端点
//		decodeSumRequest,              // 传输层解析参数函数
//		encodeResponse,                // 传输层编码响应参数函数
//	)
//
//	// 拼接字符串处理器	--> 处理HTTP请求
//	concatHandler := httptransport.NewServer(
//		endpoint.MakeConcatEndpoint(svc),
//		decodeCountRequest,
//		encodeResponse,
//	)
//
//	http.Handle("/sum", sumHandler)
//	http.Handle("/concat", concatHandler)
//
//	// 开启协程启动HTTP服务
//	go func() {
//		log.Fatal(http.ListenAndServe(":8080", nil))
//	}()
//
//	// GRPC
//
//	// 创建gRpc服务
//	gs := NewGRPCServer(svc)
//	// 监听Rpc端口
//	listener, err := net.Listen("tcp", ":8972")
//	if err != nil {
//		panic(err)
//	}
//	server := grpc.NewServer()          // 创建GRPC服务器
//	proto.RegisterAddServer(server, gs) // 注册grpc服务
//	// 启动服务
//	go func() {
//		err = server.Serve(listener)
//		if err != nil {
//			log.Fatal(err)
//		}
//	}()
//}

//----------------------grpc请求------------------------------------

// 接收grpc请求
type grpcServer struct {
	proto.UnimplementedAddServer
	sum    grpctransport.Handler
	concat grpctransport.Handler
}

// Sum 求和 相当于做了个转发, 接收RPC请求, 绑定端点的的时候指定参数转换函数, 调用端点的函数
func (s *grpcServer) Sum(ctx context.Context, req *proto.SumRequest) (*proto.SumResponse, error) {
	_, rep, err := s.sum.ServeGRPC(ctx, req)
	if err != nil {
		return nil, err
	}
	return rep.(*proto.SumResponse), nil
}

// Concat 拼接字符串
func (s *grpcServer) Concat(ctx context.Context, req *proto.ConcatRequest) (*proto.ConcatResponse, error) {
	_, resp, err := s.concat.ServeGRPC(ctx, req)
	if resp != nil {
		return nil, err
	}
	return resp.(*proto.ConcatResponse), nil
}

// NewGRPCServer 构造函数 创建GRPC服务
func NewGRPCServer(svc service.AddService) proto.AddServer {
	return &grpcServer{
		sum: grpctransport.NewServer(
			endpoint.MakeSumEndpoint(svc),
			decodeGRPCSumRequest,
			encodeGRPCSumResponse,
		),
		concat: grpctransport.NewServer(
			endpoint.MakeConcatEndpoint(svc),
			decodeGRPCConcatRequest,
			encodeGRPCConcatResponse,
		),
	}
}

// 处理gRpc请求的编解码函数

// decodeGRPCSumRequest 处理求和的grpc参数
func decodeGRPCSumRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
	req := grpcReq.(*proto.SumRequest) // 断言, 转换类型
	return endpoint.SumRequest{A: int(req.A), B: int(req.B)}, nil
}

// decodeGRPCConcatRequest 处理拼接字符串的gRPC请求
func decodeGRPCConcatRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
	req := grpcReq.(*proto.ConcatRequest)
	return endpoint.ConcatRequest{
		A: req.A,
		B: req.B,
	}, nil
}

// encodeGRPCSumResponse 编码求和函数响应结果
func encodeGRPCSumResponse(_ context.Context, response interface{}) (interface{}, error) {
	resp := response.(endpoint.SumResponse)
	return &proto.SumResponse{V: int64(resp.V), Err: resp.Err}, nil
}

// encodeGRPCConcatResponse 编码拼接字符串函数系响应结果
func encodeGRPCConcatResponse(_ context.Context, response interface{}) (interface{}, error) {
	resp := response.(endpoint.ConcatResponse)
	return &proto.ConcatResponse{V: resp.V, Err: resp.Err}, nil
}
